`timescale 1ns / 1ps

module tb_IIR_3_core;

parameter datin_width = 16;
parameter daout_width = 16;
parameter index_bit = 12;
parameter index_max = 10;

// 时钟周期
reg clk;
initial clk = 0;
always #5 clk = ~clk;

reg rst_n;
reg en_flag;
wire busy;
reg [index_bit-1:0] index = 0;

// DUT 实例化
wire [datin_width-1:0] datin_bram_r_data;
wire datin_bram_r_we;
wire datin_bram_r_en;
wire [index_bit-1:0] datin_bram_r_addr;

wire [daout_width-1:0] daout_bram_w_data;
wire daout_bram_w_we;
wire daout_bram_w_en;
wire [index_bit-1:0] daout_bram_w_addr;

wire [datin_width*8-1:0] cache_bram_w_data;
wire cache_bram_w_we;
wire cache_bram_w_en;
wire [index_bit-1:0] cache_bram_w_addr;

wire [datin_width*8-1:0] cache_bram_r_data;
wire cache_bram_r_we;
wire cache_bram_r_en;
wire [index_bit-1:0] cache_bram_r_addr;

// 模拟 BRAM 存储
reg [datin_width-1:0] datin_bram_mem [0:index_max-1];
reg [datin_width*8-1:0] cache_bram_mem [0:index_max-1];
reg [daout_width-1:0] daout_bram_mem [0:index_max-1];

// BRAM读取延迟逻辑（在 en 拉高的同一周期内返回数据）
reg [datin_width-1:0] datin_bram_r_data_reg;
reg [datin_width*8-1:0] cache_bram_r_data_reg;
assign datin_bram_r_data = datin_bram_r_data_reg;
assign cache_bram_r_data = cache_bram_r_data_reg;



always @(posedge clk) begin
    if (datin_bram_r_en) begin
        datin_bram_r_data_reg <= datin_bram_mem[datin_bram_r_addr];
    end
    if (cache_bram_r_en) begin
        cache_bram_r_data_reg <= cache_bram_mem[cache_bram_r_addr];
    end
end

// 写回逻辑
always @(posedge clk) begin
    if (daout_bram_w_en && daout_bram_w_we)
        daout_bram_mem[daout_bram_w_addr] <= daout_bram_w_data;
    if (cache_bram_w_en && cache_bram_w_we)
        cache_bram_mem[cache_bram_w_addr] <= cache_bram_w_data;
end

// 初始化和启动
integer i, round;
initial begin
    rst_n = 0;
    en_flag = 0;

    // 初始化 BRAM 内容
    for (i = 0; i < index_max; i = i + 1) begin
        datin_bram_mem[i] = i;                // datin 为 index
        cache_bram_mem[i] = 0;                // 初始 cache 清零
        daout_bram_mem[i] = 0;
    end

    #20;
    rst_n = 1;
    #20;
    
    // 进行多轮计算
    for (round = 0; round < 3; round = round + 1) begin
        $display("==== Starting Round %0d ====", round + 1);
        
        // 发出启动信号
        #5
        en_flag = 1;
        #10;
        en_flag = 0;

        // 等待 busy 拉低
        wait (busy == 1);
        wait (busy == 0);
        
        // 显示当前轮次结果
        $display("==== Round %0d Results ====", round + 1);
        for (i = 0; i < index_max; i = i + 1) begin
            $display("Index %0d: Input = %0d, Output = %0d", i, datin_bram_mem[i], daout_bram_mem[i]);
        end
        
        // 准备下一轮输入数据（简单递增）
        for (i = 0; i < index_max; i = i + 1) begin
            datin_bram_mem[i] = datin_bram_mem[i] + index_max;
        end
        
        #20; // 轮次间间隔
    end
    
    $display("==== Final Simulation Results ====");
    for (i = 0; i < index_max; i = i + 1) begin
        $display("Index %0d: Final Output = %0d", i, daout_bram_mem[i]);
    end
    $finish;
end

IIR_3_core #(
    .datin_width(datin_width),
    .daout_width(daout_width),
    .index_bit(index_bit),
    .index_max(index_max)
) uut (
    .clk(clk),
    .rst_n(rst_n),
    .en_flag(en_flag),
    .busy(busy),
    .datin_bram_r_data(datin_bram_r_data),
    .datin_bram_r_we(datin_bram_r_we),
    .datin_bram_r_en(datin_bram_r_en),
    .datin_bram_r_addr(datin_bram_r_addr),
    .daout_bram_w_data(daout_bram_w_data),
    .daout_bram_w_we(daout_bram_w_we),
    .daout_bram_w_en(daout_bram_w_en),
    .daout_bram_w_addr(daout_bram_w_addr),
    .cache_bram_w_data(cache_bram_w_data),
    .cache_bram_w_we(cache_bram_w_we),
    .cache_bram_w_en(cache_bram_w_en),
    .cache_bram_w_addr(cache_bram_w_addr),
    .cache_bram_r_data(cache_bram_r_data),
    .cache_bram_r_we(cache_bram_r_we),
    .cache_bram_r_en(cache_bram_r_en),
    .cache_bram_r_addr(cache_bram_r_addr)
);

endmodule